import Dingo.API as api
import os, random, socket, string, time

port = 8081
host = socket.gethostname()
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

__author__ = 'Sarah Mount'

class TheSimulation(api.Simulation):
	def __init__(self, graph):
		ether = api.Ether(self)
		api.Ether.RF_radius = 500
		num_nodes = 5
		b_sensor = SocketSensor(graph, ether, -1, num_nodes)
		sensors = [ReceivingSensor(graph, ether, i, num_nodes) for i in xrange(num_nodes)]
		sensors.append(b_sensor)
		api.Simulation.__init__(self, sensors, graph)
	def run(self):
		super(TheSimulation, self).run()

class SocketSensor(api.Sensor):
    def __init__(self, graph, ether, i, num_nodes):
        # Sensor data
        x = random.randrange(400)
        y = random.randrange(400)
        self.sensor_data = []
        # Call superclass constructor
        api.Sensor.__init__(self, graph, "Sensor%d" % i, (x, y), api.SensorColor.White, api.Scheduler([BroadcastTask(self), SocketTask(self)], -1), ether)

class ReceivingSensor(api.Sensor):
	def __init__(self, graph, ether, i, num_nodes):
		x = random.randrange(400)
		y = random.randrange(500)
		api.Sensor.__init__(self, graph, "Sensor%d" % i, (x, y), api.SensorColor.Grey, api.Scheduler([RecvTask(self)], -1), ether)
		# Set up charting
		self.node.SetPlotAxes((-0.2, 1.2), 15)
		self.node.SetPlotLegend({api.SensorColour.Blue:'Probe reading'})
		self.node.SetPlotAxisLabels('Sensor Readings', 'Time', 'Value')
		return


class ReqDataPacket(api.Packet):
	"""Data request packet.
	"""
	def __init__(self, sender):
		### sending node, receiving node, message_object
		### NOTE that we haven't given a receiving object,
		### because these packets will be broadcast
		api.Packet.__init__(self, sender, None, 'REQ_DATA')
		return

class DataPacket(api.Packet):
	"""Data packet.
	"""
	def __init__(self, send_node, recv_node, msg):
		api.Packet.__init__(self, send_node, recv_node, msg)
		return

class BroadcastTask(api.Task):
	"""Broadcast a ReqDataPacket to all sensors."""
	def __init__(self, sensor):
		# self, priority, repetitions, ref-to-sensor
		api.Task.__init__(self, 0, 1, sensor)
	def task(self):
		### Debug info
		node = self.sensor.node # graphical sensor
		node.SetNodeColour(api.SensorColor.FromName("Green"))
		### Broadcast packet
		packet = ReqDataPacket(self.sensor.id)
		self.sensor.broadcast(api.SensorColor.FromName("Green"), None, packet)
		### Sleeeeep
		sleeptime = random.uniform(1, 2)
		api.Sleep(sleeptime)
		return

class SocketTask(api.Task):
	"""Send data average to plotter via socket."""
	def __init__(self, sensor):
		# self, priority, repetitions, ref-to-sensor
		api.Task.__init__(self, 0, 1, sensor)
		self.counter = 0
	def task(self):
		### Debug info
		node = self.sensor.node # graphical sensor
		node.SetNodeColour(api.SensorColor.FromName("Green"))
		# Real work!
		while not self.sensor.recv_q.empty(): # If there are any messages
			msg = self.sensor.recv_q.get()
			self.sensor.sensor_data.append(msg.msg)
		# Send data over socket once every so many iterations
		p = random.random()
		if p < 0.5 and self.sensor.sensor_data:
			# Average sensor data
			average = sum(self.sensor.sensor_data, 0.0) / len(self.sensor.sensor_data)
			#rounded_data = map(lambda x: round(x, 2), self.sensor.sensor_data)
			# Send data down socket
			s = self.sensor.id + '\t' + str(self.counter) + '\t' + str(average)
            		sock.sendto(s, (host, port))
            		print 'sending:', s
			# Reset sensor data
			self.sensor.sensor_data = []
			self.counter += 1
		### Sleep
		sleeptime = random.uniform(1, 2)
		api.Sleep(sleeptime)
		return

class RecvTask(api.Task):
	"""Iterate over recv_q; retrieve packets and change colour."""
	def __init__(self, sensor):
		# self, priority, repetitions, ref-to-sensor
		api.Task.__init__(self, 0, 2, sensor)
	def task(self):
		### Debug info
		node = self.sensor.node # graphical sensor
		node.SetNodeColour(api.SensorColor.FromName("Black"))
		### Real work
		if self.sensor.recv_q.empty():
			return
		while not self.sensor.recv_q.empty(): # If there are any messages
			msg = self.sensor.recv_q.get()
			# Send data packet
			node.SetNodeColour(api.SensorColor.FromName("Red"))
			datum = random.random()
			packet = DataPacket(self.sensor.id, msg.sender_id, datum)
			self.sensor.send_q.put(packet) 
			self.sensor.send(api.SensorColor.FromName("Dim Grey"))
			# Chart that datum
			node.AddPlotData(datum)
			### Sleep
			sleeptime = random.uniform(1, 2)
			api.Sleep(sleeptime)
		return
		
